#include "button_ctrl.h"
#include "buttons.h"
#include "utils.h"
#include "configs.h"
#include "lcd_ctrl.h"
#include "history.h"
#include "fsl_debug_console.h"
#include <tos_k.h>


#define N_SECONDS_FULL_SCREEN (CONF_X_AXIS_SCALE_STEP * CONF_X_AXIS_N_SCALES / 1000)
#define N_SCALESS_FULL_SCREEN (CONF_X_AXIS_SCALE_SECTION_N_POINTS * CONF_X_AXIS_N_SCALES)


typedef enum btn_ctrl_do_what_t
{
    BTN_CTRL_NOTHING,
    BTN_CTRL_F1_F2_PRESSED,
    BTN_CTRL_F1_F2_RELEASED,
    BTN_CTRL_F1_CLICK,
    BTN_CTRL_F2_CLICK,
    BTN_CTRL_F1_LONG_PRESSED,
    BTN_CTRL_F2_LONG_PRESSED,
} btn_ctrl_do_what_t;

typedef struct btn_ctrl_status_t
{
    int btn_status[BTN_ID_COUNT];
    btn_ctrl_do_what_t do_what;
} btn_ctrl_status_t;


static k_task_t g_btn_ctrl_task;
static k_mutex_t g_btn_ctrl_mutex;
static uint8_t g_task_stk[2048];
static uint8_t g_run = 0;
static k_tick_t g_day_begin = 0;

static btn_ctrl_status_t g_btn_ctrl_status = {
    .btn_status = { 0 },
    .do_what = BTN_CTRL_NOTHING,
};


static void btn_F1_on_event(int event)
{
    tos_mutex_pend(&g_btn_ctrl_mutex);
    g_btn_ctrl_status.btn_status[BTN_ID_1] = event;
    tos_mutex_post(&g_btn_ctrl_mutex);
}

static void btn_F2_on_event(int event)
{
    tos_mutex_pend(&g_btn_ctrl_mutex);
    g_btn_ctrl_status.btn_status[BTN_ID_2] = event;
    tos_mutex_post(&g_btn_ctrl_mutex);
}

static void btn_ctrl_do_what(btn_ctrl_do_what_t do_what)
{
    {  // Update the day
        day_t day_old = k_tick_t_2_day_t(g_day_begin);
        day_t day_cur = k_tick_t_2_day_t(get_sys_time());
        if (day_old != day_cur)
        {
            g_day_begin = day_t_2_k_tick_t(day_cur);
        }
    }
    switch (do_what)
    {
    case BTN_CTRL_F1_F2_PRESSED:
        PRINTF("BTN_CTRL_F1_F2_PRESSED\r\n");
        if (ELEC_MODE_SECOND == get_elec_mode())
        {
            set_elec_mode(ELEC_MODE_DAY);
            k_tick_t t = get_sys_time();
            day_t d = k_tick_t_2_day_t(t) - N_SCALESS_FULL_SCREEN + 1;
            if (d > history_get_first_day())
            {
                t = day_t_2_k_tick_t(d);
            } else
            {
                t = day_t_2_k_tick_t(history_get_first_day());
            }
            update_elec_time_begin(&t);
        } else
        {
            set_elec_mode(ELEC_MODE_SECOND);
            k_tick_t t = get_sys_time();
            int t_ = k_tick_t_2_day_seconds(t);
            if (t_ < N_SECONDS_FULL_SCREEN)
            {
                t = day_t_2_k_tick_t(k_tick_t_2_day_t(t_));
            } else
            {
                t = t /  1000 * 1000 - N_SECONDS_FULL_SCREEN * 1000;
            }
            update_elec_time_begin(&t);
        }
        freeze_lcd(0);  // When the mode is changed, unfreeze the lcd
        force_refresh_lcd();
        break;
    case BTN_CTRL_F1_F2_RELEASED:
        PRINTF("BTN_CTRL_F1_F2_RELEASED\r\n");
        break;
    case BTN_CTRL_F1_CLICK:
        PRINTF("BTN_CTRL_F1_CLICK\r\n");
        if (ELEC_MODE_SECOND == get_elec_mode())
        {
            // Check if the values are full screen
            // {
            //     char time1[24] = {0};
            //     char time2[24] = {0};
            //     k_tick_t_2_str(update_elec_time_begin(K_NULL), time1, sizeof(time1));
            //     k_tick_t_2_str(g_day_begin, time2, sizeof(time2));
            //     PRINTF("g_day_begin: %s update_elec_time_begin(K_NULL): %s %d\r\n", time2, time1,
            //         (int) k_tick_t_2_day_seconds(get_sys_time() - g_day_begin));
            // }
            if (k_tick_t_2_day_seconds(get_sys_time()/* - g_day_begin*/) > N_SECONDS_FULL_SCREEN)
            {
                freeze_lcd(1);
                k_tick_t t = update_elec_time_begin(K_NULL);
                t -= 1000;
                update_elec_time_begin(&t);
            }
        } else
        {
            k_tick_t t = update_elec_time_begin(K_NULL);
            day_t d = k_tick_t_2_day_t(t);
            if (d > history_get_first_day())
            {
                freeze_lcd(1);
                --d;
                t = day_t_2_k_tick_t(d);
                update_elec_time_begin(&t);
            }
        }
        force_refresh_lcd();
        break;
    case BTN_CTRL_F2_CLICK:
        PRINTF("BTN_CTRL_F2_CLICK\r\n");
        if (ELEC_MODE_SECOND == get_elec_mode())
        {
            // Check if the values are full screen
            k_tick_t t = update_elec_time_begin(K_NULL);
            if ((t + N_SECONDS_FULL_SCREEN * 1000) < get_sys_time() /  1000 * 1000)  // Delete the milliseconds
            {
                PRINTF("update time begin\r\n");
                t += 1000;
                update_elec_time_begin(&t);
            } else
            {
                freeze_lcd(0);
            }
        } else
        {
            k_tick_t t = update_elec_time_begin(K_NULL);
            day_t d = k_tick_t_2_day_t(t);
            day_t cur = k_tick_t_2_day_t(get_sys_time());
            if (d + N_SCALESS_FULL_SCREEN <= cur)
            {
                freeze_lcd(1);
                ++d;
                t = day_t_2_k_tick_t(d);
                update_elec_time_begin(&t);
            } else
            {
                freeze_lcd(0);
            }
        }
        force_refresh_lcd();
        break;
    case BTN_CTRL_F1_LONG_PRESSED:
        PRINTF("BTN_CTRL_F1_LONG_PRESSED\r\n");
        if (ELEC_MODE_SECOND == get_elec_mode())
        {
            if (k_tick_t_2_day_seconds(get_sys_time()/* - g_day_begin*/) > N_SECONDS_FULL_SCREEN)
            {
                freeze_lcd(1);
                k_tick_t t = update_elec_time_begin(K_NULL);
                t -= 1000;
                update_elec_time_begin(&t);
            }
        } else
        {
            k_tick_t t = update_elec_time_begin(K_NULL);
            day_t d = k_tick_t_2_day_t(t);
            if (d > history_get_first_day())
            {
                freeze_lcd(1);
                --d;
                t = day_t_2_k_tick_t(d);
                update_elec_time_begin(&t);
            }
        }
        force_refresh_lcd();
        break;
    case BTN_CTRL_F2_LONG_PRESSED:
        PRINTF("BTN_CTRL_F2_LONG_PRESSED\r\n");
        if (ELEC_MODE_SECOND == get_elec_mode())
        {
            // Check if the values are full screen
            k_tick_t t = update_elec_time_begin(K_NULL);
            if ((t + N_SECONDS_FULL_SCREEN * 1000) < get_sys_time() /  1000 * 1000)  // Delete the milliseconds
            {
                PRINTF("update time begin\r\n");
                t += 1000;
                update_elec_time_begin(&t);
            } else
            {
                freeze_lcd(0);
            }
        } else
        {
            k_tick_t t = update_elec_time_begin(K_NULL);
            day_t d = k_tick_t_2_day_t(t);
            day_t cur = k_tick_t_2_day_t(get_sys_time());
            if (d + N_SCALESS_FULL_SCREEN <= cur)
            {
                freeze_lcd(1);
                ++d;
                t = day_t_2_k_tick_t(d);
                update_elec_time_begin(&t);
            } else
            {
                freeze_lcd(0);
            }
        }
        force_refresh_lcd();
        break;
    default:
        break;
    }
}

static void btn_ctrl_main(void * arg)
{
    while (g_run)
    {
        btn_ctrl_do_what_t do_what = BTN_CTRL_NOTHING;
        tos_mutex_pend(&g_btn_ctrl_mutex);
        if (BTN_CTRL_F1_F2_PRESSED != g_btn_ctrl_status.do_what)
        {
            if ((g_btn_ctrl_status.btn_status[BTN_ID_1] & BTN_EVENT_PRESSED) 
                && (g_btn_ctrl_status.btn_status[BTN_ID_2] & BTN_EVENT_PRESSED))
            {
                g_btn_ctrl_status.do_what = do_what = BTN_CTRL_F1_F2_PRESSED;
                g_btn_ctrl_status.btn_status[BTN_ID_1] = BTN_EVENT_PRESSED;
                g_btn_ctrl_status.btn_status[BTN_ID_2] = BTN_EVENT_PRESSED;
            } else if (BTN_EVENT_LONG_PRESS & g_btn_ctrl_status.btn_status[BTN_ID_1])
            {
                g_btn_ctrl_status.do_what = BTN_CTRL_NOTHING;
                do_what = BTN_CTRL_F1_LONG_PRESSED;
                g_btn_ctrl_status.btn_status[BTN_ID_1] = BTN_EVENT_LONG_PRESS;
            } else if (BTN_EVENT_LONG_PRESS & g_btn_ctrl_status.btn_status[BTN_ID_2])
            {
                g_btn_ctrl_status.do_what = BTN_CTRL_NOTHING;
                do_what = BTN_CTRL_F2_LONG_PRESSED;
                g_btn_ctrl_status.btn_status[BTN_ID_2] = BTN_EVENT_LONG_PRESS;
            } else if (BTN_EVENT_CLICK & g_btn_ctrl_status.btn_status[BTN_ID_1])
            {
                g_btn_ctrl_status.do_what = BTN_CTRL_NOTHING;
                do_what = BTN_CTRL_F1_CLICK;
                g_btn_ctrl_status.btn_status[BTN_ID_1] = BTN_EVENT_RELEASED;
            } else if (BTN_EVENT_CLICK & g_btn_ctrl_status.btn_status[BTN_ID_2])
            {
                g_btn_ctrl_status.do_what = BTN_CTRL_NOTHING;
                do_what = BTN_CTRL_F2_CLICK;
                g_btn_ctrl_status.btn_status[BTN_ID_2] = BTN_EVENT_RELEASED;
            }
        } else 
        {
            if ((g_btn_ctrl_status.btn_status[BTN_ID_1] & BTN_EVENT_RELEASED) 
                && (g_btn_ctrl_status.btn_status[BTN_ID_2] & BTN_EVENT_RELEASED))
            {
                g_btn_ctrl_status.do_what = BTN_CTRL_NOTHING;
                do_what = BTN_CTRL_F1_F2_RELEASED;
                g_btn_ctrl_status.btn_status[BTN_ID_1] = BTN_EVENT_RELEASED;
                g_btn_ctrl_status.btn_status[BTN_ID_2] = BTN_EVENT_RELEASED;
            }
        }
        tos_mutex_post(&g_btn_ctrl_mutex);

        btn_ctrl_do_what(do_what);

        tos_task_delay(10);
    }
}

void btn_ctrl_init(void)
{
    g_day_begin = update_elec_time_begin(K_NULL);
    buttons_init();
	buttons_set_callback(BTN_ID_1, btn_F1_on_event);
	buttons_set_callback(BTN_ID_2, btn_F2_on_event);
	tos_mutex_create(&g_btn_ctrl_mutex);
    g_run = 1;
    tos_task_create(&g_btn_ctrl_task, "btn_ctrl_main", btn_ctrl_main, NULL, 4, g_task_stk, sizeof(g_task_stk), 0);
}

void btn_ctrl_deinit(void)
{
    // TODO:
}
